import { calculateVideoDimensions, applyVideoDimensionsStyle } from './videoDimensions'

/**
 * 鼠标事件处理类
 * 用于处理视频播放器的鼠标交互事件，包括拖拽、点击、双击等
 *
 * @example
 * ```js
 * // 创建鼠标事件处理实例
 * const mouseHandler = new MouseEventHandler('video-container', {
 *   aspectRatio: '16/9',      // 视频宽高比
 *   moveThreshold: 5,         // 移动阈值(像素)
 *   clickDelay: 200,         // 双击延迟(毫秒)
 *   ratioThreshold: 10,      // 比例阈值(%)
 *   throttleTime: 16,        // 节流时间(毫秒)
 *   eventHandlers: {         // 事件处理函数
 *     click: () => console.log('点击'),
 *     doubleClick: () => console.log('双击'),
 *     dragStart: () => console.log('开始拖拽'),
 *     dragging: () => console.log('拖拽中'),
 *     dragEnd: () => console.log('结束拖拽')
 *   }
 * })
 *
 * // 销毁实例
 * mouseHandler.destroy()
 * ```
 */
export default class MouseEventHandler {
  constructor(element, config = {}) {
    this.element = typeof element === 'string' ? document.getElementById(element) : element
    this.config = config
    this.isMousedown = false
    this.isDragging = false
    this.startX = 0
    this.startY = 0
    this.endX = 0
    this.endY = 0
    this.xOffset = 0
    this.yOffset = 0
    this.xOffsetRatio = 0
    this.yOffsetRatio = 0
    this.isLeftMove = false
    this.isRightMove = false
    this.isUpMove = false
    this.isDownMove = false
    this.playerWidth = 0
    this.playerHeight = 0
    this.videoOffsetLeft = 0 // 视频区域相对于容器左侧的偏移量
    this.clickTimeout = null // 点击事件的超时ID
    this.MOVE_THRESHOLD = config.moveThreshold || 5 // 5px 内不触发事件
    this.CLICK_DELAY = config.clickDelay || 200 // 200ms 内触发双击事件
    this.RATIO_THRESHOLD = config.ratioThreshold || 10 // 阈值比例 10%
    this.THROTTLE_TIME = config.throttleTime || 0 // 节流时间
    this.aspectRatio = config.aspectRatio || '16/9' // 视频宽高比，默认16:9

    // 节流后的拖拽处理函数
    this.throttledDragging = throttle(this.handleDragging.bind(this), this.THROTTLE_TIME)
    this.eventHandlers = config.eventHandlers || {} // 事件处理器

    // 延迟创建视频尺寸的DIV元素，确保DOM已加载
    this.createVideoElementWithRetry()

    // 绑定事件会在创建元素后进行
  }

  // 创建视频元素，带有重试机制
  createVideoElementWithRetry(retryCount = 0) {
    const maxRetries = 3
    const retryDelay = 300 // 毫秒

    // 如果容器尺寸为0且未超过最大重试次数，则延迟重试
    if ((this.element.offsetHeight === 0 || this.element.offsetWidth === 0) && retryCount < maxRetries) {
      //
      setTimeout(() => {
        this.createVideoElementWithRetry(retryCount + 1)
      }, retryDelay)
      return
    }

    // 创建视频元素
    this.createVideoElement()

    // 创建完成后绑定事件
    if (this.videoElement) {
      this.bindEvents()
    }
  }

  // 创建一个与实际视频大小相同的div元素
  createVideoElement() {
    // 获取容器元素的尺寸
    let containerHeight = this.element.clientHeight
    let containerWidth = this.element.clientWidth

    // 检查容器尺寸，如果为0，使用默认值
    if (containerHeight === 0 || containerWidth === 0) {
      console.warn('警告：容器尺寸为0，使用默认尺寸', {
        originalHeight: containerHeight,
        originalWidth: containerWidth
      })

      containerHeight = this.element.clientHeight || parseInt(this.element.style.height) || 400
      containerWidth = this.element.clientWidth || parseInt(this.element.style.width) || 600
    }

    // 计算视频尺寸
    const dimensions = calculateVideoDimensions({
      containerWidth,
      containerHeight,
      aspectRatio: this.aspectRatio
    })

    // 确保容器元素有相对定位，用于正确定位视频元素
    const containerPosition = window.getComputedStyle(this.element).position
    if (containerPosition !== 'relative' && containerPosition !== 'absolute') {
      this.element.style.position = 'relative'
    }

    // 创建视频div元素
    this.videoElement = document.createElement('div')
    this.videoElement.className = 'video-handler-element'

    // 应用尺寸和样式
    applyVideoDimensionsStyle(this.videoElement, dimensions)
    this.videoElement.style.zIndex = '2' // 确保元素在最上层

    // 添加背景色，便于调试（可选，生产环境可移除）
    if (this.config.debug) {
      this.videoElement.style.backgroundColor = 'rgba(0, 255, 0, 0.1)'
      this.videoElement.style.border = '1px dashed rgba(0, 0, 255, 0.4)'
    }

    // 添加到容器中
    this.element.appendChild(this.videoElement)

    // 存储视频尺寸和偏移量
    this.playerWidth = dimensions.width
    this.playerHeight = dimensions.height
    this.videoOffsetLeft = dimensions.margin

    // console.log('创建视频元素:', {
    //   containerWidth,
    //   containerHeight,
    //   ...dimensions,
    //   elementCreated: !!this.videoElement
    // })
  }

  // 获取播放器的真实宽高
  getPlayerDimensions() {
    if (!this.element) {
      console.error('Element is not found.')
      return { width: 0, height: 0 }
    }

    if (this.videoElement) {
      // 直接返回已创建的视频元素尺寸
      return {
        width: parseFloat(this.videoElement.style.width),
        height: parseFloat(this.videoElement.style.height)
      }
    }

    // 获取容器尺寸
    const containerHeight = this.element.offsetHeight
    const containerWidth = this.element.offsetWidth

    // 计算视频尺寸
    const dimensions = calculateVideoDimensions({
      containerWidth,
      containerHeight,
      aspectRatio: this.aspectRatio
    })

    // 存储左侧偏移量
    this.videoOffsetLeft = dimensions.margin

    console.log('计算播放器尺寸:', {
      containerWidth,
      containerHeight,
      ...dimensions
    })

    // 返回计算后的尺寸
    return {
      width: dimensions.width,
      height: dimensions.height
    }
  }

  // 更新视频元素尺寸，响应窗口大小变化
  updateVideoElement(forceUpdate = false) {
    if (!this.element || !this.videoElement) return

    let containerHeight = this.element.clientHeight
    let containerWidth = this.element.clientWidth

    // 检查容器尺寸，如果为0且不是强制更新，则跳过
    if ((containerHeight === 0 || containerWidth === 0) && !forceUpdate) {
      console.warn('更新视频元素失败: 容器尺寸为0')
      return
    }

    // 如果尺寸仍为0，但需要强制更新，则使用默认值
    if ((containerHeight === 0 || containerWidth === 0) && forceUpdate) {
      containerHeight = this.element.clientHeight || parseInt(this.element.style.height) || 400
      containerWidth = this.element.clientWidth || parseInt(this.element.style.width) || 600
    }

    // 计算视频尺寸
    const dimensions = calculateVideoDimensions({
      containerWidth,
      containerHeight,
      aspectRatio: this.aspectRatio
    })

    // 应用尺寸和样式
    applyVideoDimensionsStyle(this.videoElement, dimensions)

    // 更新存储的视频尺寸和偏移量
    this.playerWidth = dimensions.width
    this.playerHeight = dimensions.height
    this.videoOffsetLeft = dimensions.margin
  }

  // 将容器坐标转换为视频坐标
  convertToVideoCoordinates(x, y) {
    // 由于事件现在直接绑定在视频元素上，x和y已经是相对于视频元素的坐标，无需转换
    // 仅需确保坐标在视频区域内
    const boundedX = Math.max(0, Math.min(x, this.playerWidth))
    const boundedY = Math.max(0, Math.min(y, this.playerHeight))

    return { x: boundedX, y: boundedY }
  }

  // 绑定鼠标事件到视频元素
  bindEvents() {
    if (!this.videoElement) return

    const eventNames = ['mouseleave', 'mousedown', 'mousemove', 'mouseup', 'wheel']
    eventNames.forEach((event) => {
      this.videoElement.addEventListener(event, this[`handle${capitalizeFirstLetter(event)}`].bind(this))
    })

    // 为容器添加窗口大小变化监听
    window.addEventListener('resize', this.handleResize.bind(this))
  }

  // 窗口大小变化事件处理
  handleResize() {
    this.updateVideoElement()
  }

  // 清理事件
  destroy() {
    if (this.videoElement) {
      const eventNames = ['mouseleave', 'mousedown', 'mousemove', 'mouseup', 'wheel']
      eventNames.forEach((event) => {
        this.videoElement.removeEventListener(event, this[`handle${capitalizeFirstLetter(event)}`].bind(this))
      })

      // 移除窗口大小变化监听
      window.removeEventListener('resize', this.handleResize.bind(this))

      // 从容器中移除视频元素
      if (this.element.contains(this.videoElement)) {
        this.element.removeChild(this.videoElement)
      }

      this.videoElement = null
    }
  }

  // 鼠标按下事件
  handleMousedown(event) {
    this.startX = event.offsetX
    this.startY = event.offsetY
    this.isMousedown = true
    this.isDragging = false
    this.triggerEvent('mousedown')
  }

  // 鼠标移动事件
  handleMousemove(event) {
    if (!this.isMousedown) return

    const x = event.offsetX
    const y = event.offsetY

    if (Math.abs(x - this.startX) > this.MOVE_THRESHOLD || Math.abs(y - this.startY) > this.MOVE_THRESHOLD) {
      this.isDragging = true
    }

    if (this.isDragging) {
      this.throttledDragging(event) // 使用节流函数来处理拖拽
    }
  }

  // 鼠标松开事件
  handleMouseup(event) {
    if (!this.isMousedown) {
      this.isMousedown = false
      return
    }

    // 取消未执行的节流操作
    this.throttledDragging.cancel()

    this.endX = event.offsetX
    this.endY = event.offsetY

    this.isMousedown = false
    if (this.isDragging) {
      this.isDragging = false
      this.videoElement.style.cursor = 'default'
      this.triggerEvent('dragend')
      return
    }

    if (this.clickTimeout) {
      clearTimeout(this.clickTimeout)
      this.clickTimeout = null
      this.triggerEvent('dblclick')
    } else {
      this.clickTimeout = setTimeout(() => {
        this.triggerEvent('click')
        this.clickTimeout = null
      }, this.CLICK_DELAY)
    }
  }

  // 鼠标离开事件
  handleMouseleave() {
    if (this.isMousedown) {
      this.isMousedown = false
      this.isDragging = false
      this.videoElement.style.cursor = 'default'
      this.triggerEvent('mouseleave')

      // 取消未执行的节流操作
      this.throttledDragging.cancel()
    }
  }

  // 鼠标滚轮事件
  handleWheel(event) {
    const zoom = event.deltaY < 0 ? 'in' : 'out'

    this.startX = event.offsetX
    this.startY = event.offsetY
    this.endX = event.offsetX
    this.endY = event.offsetY

    this.triggerEvent(zoom === 'in' ? 'zoomIn' : 'zoomOut')
    this.triggerEvent('wheel', { zoom })
  }

  // 鼠标拖动事件
  handleDragging(event) {
    this.videoElement.style.cursor = 'move'

    const x = event.offsetX
    const y = event.offsetY

    this.xOffset = x - this.startX
    this.yOffset = y - this.startY

    // 计算偏移比例 要正数
    this.xOffsetRatio = Math.round((Math.abs(this.xOffset) / this.playerWidth) * 100)
    this.yOffsetRatio = Math.round((Math.abs(this.yOffset) / this.playerHeight) * 100)

    // 当xOffsetRatio或yOffsetRatio超过指定比例时，触发事件并重置
    if (this.xOffsetRatio >= this.RATIO_THRESHOLD || this.yOffsetRatio >= this.RATIO_THRESHOLD) {
      // 计算滑动方向
      const moveDirection = this.calculateMoveDirection()

      const dragType = this.xOffsetRatio >= this.RATIO_THRESHOLD ? 'x' : 'y'

      // 如果 X 轴拖拽比例超过阈值，触发 X 轴拖拽事件
      if (this.xOffsetRatio >= this.RATIO_THRESHOLD) {
        this.triggerEvent('dragX', {
          xOffset: this.xOffset,
          xOffsetRatio: this.xOffsetRatio,
          moveDirection: moveDirection, // 传递方向信息
          dragType: 'x' // 标识当前为X轴拖拽事件
        })
      }

      // 如果 Y 轴拖拽比例超过阈值，触发 Y 轴拖拽事件
      if (this.yOffsetRatio >= this.RATIO_THRESHOLD) {
        this.triggerEvent('dragY', {
          yOffset: this.yOffset,
          yOffsetRatio: this.yOffsetRatio,
          moveDirection: moveDirection, // 传递方向信息
          dragType: 'y' // 标识当前为Y轴拖拽事件
        })
      }

      // 触发事件时，加入方向信息
      this.triggerEvent('drag', {
        xOffset: this.xOffset,
        yOffset: this.yOffset,
        xOffsetRatio: this.xOffsetRatio,
        yOffsetRatio: this.yOffsetRatio,
        moveDirection: moveDirection, // 传递方向信息
        dragType
      })

      // 更新起始点
      this.startX = x
      this.startY = y
      this.xOffset = 0
      this.yOffset = 0
      this.xOffsetRatio = 0
      this.yOffsetRatio = 0
    }
  }

  // 计算移动方向
  calculateMoveDirection() {
    this.isLeftMove = this.xOffset < 0
    this.isRightMove = this.xOffset > 0
    this.isUpMove = this.yOffset < 0
    this.isDownMove = this.yOffset > 0

    // 根据 xOffset 和 yOffset 的组合，返回复合方向
    if (this.isLeftMove && this.isUpMove) return 'left-up'
    if (this.isLeftMove && this.isDownMove) return 'left-down'
    if (this.isRightMove && this.isUpMove) return 'right-up'
    if (this.isRightMove && this.isDownMove) return 'right-down'

    // 单一方向
    if (this.isLeftMove) return 'left'
    if (this.isRightMove) return 'right'
    if (this.isUpMove) return 'up'
    if (this.isDownMove) return 'down'

    // 如果没有移动，返回空字符串
    return ''
  }

  // 触发事件
  triggerEvent(eventType, additionalParams = {}) {
    const params = {
      eventType,
      startX: this.startX,
      startY: this.startY,
      endX: this.endX,
      endY: this.endY,
      playerWidth: this.playerWidth,
      playerHeight: this.playerHeight,
      ...additionalParams
    }

    // 调用外部传入的事件处理器
    if (this.eventHandlers[eventType]) {
      this.eventHandlers[eventType](params)
    }
  }

  // 更新视频尺寸（可在窗口大小变化时调用）
  updatePlayerDimensions() {
    this.updateVideoElement()
  }
}

// 帮助函数：节流函数
function throttle(func, limit) {
  let lastFunc
  let lastRan

  // 增加一个取消函数
  const throttled = (...args) => {
    if (!lastRan) {
      func.apply(this, args)
      lastRan = Date.now()
    } else {
      clearTimeout(lastFunc)
      lastFunc = setTimeout(
        () => {
          if (Date.now() - lastRan >= limit) {
            func.apply(this, args)
            lastRan = Date.now()
          }
        },
        limit - (Date.now() - lastRan)
      )
    }
  }

  // 增加取消功能，允许在外部调用以停止未执行的节流操作
  throttled.cancel = function () {
    clearTimeout(lastFunc)
  }

  return throttled
}

// 帮助函数：首字母大写
function capitalizeFirstLetter(string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}
